package com.itheima.app.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.app.exception.BusinessException;
import com.itheima.app.interceptor.UserHolder;
import com.itheima.autoconfig.aip.AipFaceTemplate;
import com.itheima.autoconfig.im.HuanXinTemplate;
import com.itheima.autoconfig.oss.OssTemplate;
import com.itheima.autoconfig.sms.SmsTemplate;
import com.itheima.domain.db.Log;
import com.itheima.domain.db.User;
import com.itheima.domain.db.UserInfo;
import com.itheima.domain.mongo.Friend;
import com.itheima.domain.mongo.RecommendUser;
import com.itheima.domain.mongo.UserLike;
import com.itheima.domain.mongo.Visitor;
import com.itheima.enums.FriendsType;
import com.itheima.service.db.UserInfoService;
import com.itheima.service.db.UserLikeApi;
import com.itheima.service.db.UserService;
import com.itheima.service.mongo.FriendService;
import com.itheima.service.mongo.RecommendUserService;
import com.itheima.service.mongo.VisitorService;
import com.itheima.util.ConstantUtil;
import com.itheima.util.Constants;
import com.itheima.util.JwtUtil;
import com.itheima.vo.*;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

@Component

public class UserManager {

    @DubboReference
    UserService userService;

    @Autowired
    SmsTemplate smsTemplate;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @DubboReference
    UserInfoService userInfoService;

    @Autowired
    AipFaceTemplate aipFaceTemplate;

    @Autowired
    OssTemplate ossTemplate;

    @Autowired
    HuanXinTemplate huanXinTemplate;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @DubboReference
    RecommendUserService recommendUserService;


    @DubboReference
    VisitorService visitorService;


    @DubboReference
    UserLikeApi userLikeApi;

    @DubboReference
    FriendService friendService;



    public Long save(User user) {
        //设置一个初始化密码
        user.setPassword(ConstantUtil.INIT_PASSWORD);

        return userService.save(user);
    }

    public User findByMobile(String mobile) {
        return userService.findByMobile(mobile);
    }

    public void sendCode(String phone) {
        //1.生成随机验证码(6位数字)-使用hutool
        String code = RandomUtil.randomNumbers(6);
        //TODO 为了开发简单,发送固定的验证码"123456",等项目上线了,在发送随机
        code = "123456";

        //2.调用smsTemplate发送验证码
        //TODO 项目上线了再把这行代码打开
        //smsTemplate.sendSms(phone,code);

        //3.将验证码存入redis中,且设置时效5分钟
        stringRedisTemplate.opsForValue().set(ConstantUtil.SMS_CODE + phone, code, Duration.ofMinutes(5));
    }

    public ResponseEntity regAndLogin(Map<String, String> map) {
        //1.获取手机号和验证码
        String phone = map.get("phone");
        String verificationCode = map.get("verificationCode");

        //2.判断验证码和redis中是否相同,若不相同返回错误提示
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        String redisCode = operations.get(ConstantUtil.SMS_CODE + phone);

        //使用hutools
        if (!StrUtil.equals(verificationCode, redisCode)) {
            //return ResponseEntity.status(500).body("请输入正确的验证码");
            return ResponseEntity.status(500).body(ErrorResult.loginError());
        }

        //3.远程调用service,查询手机号是否存在
        User user = userService.findByMobile(phone);

        boolean isNew;
        //3.1 若存在 isNew=false
        if (user != null) {
            isNew = false;
        } else {
            //3.2 若不存在 isNew=true,封装user数据,保存到数据库中
            isNew = true;

            user = new User();
            user.setMobile(phone);
            user.setPassword(ConstantUtil.INIT_PASSWORD);

            Long id = userService.save(user);
            //别忘记给用户设置id
            user.setId(id);

            //往环信上注册下
            huanXinTemplate.register("HX" + id);
        }

        //4.准备用户数据(id,手机号),生成token
        Map<String, Object> userMap = new HashMap<>();
        userMap.put("id", user.getId());
        userMap.put("mobile", user.getMobile());

        //冻结登录
        LettuceConnectionFactory connectionFactory =(LettuceConnectionFactory) stringRedisTemplate.getConnectionFactory();
        if(connectionFactory!=null){
            connectionFactory.setDatabase(2);
            stringRedisTemplate.setConnectionFactory(connectionFactory);
            connectionFactory.resetConnection();
            connectionFactory.afterPropertiesSet();
        }
        String freezingRange=new String();
        if(stringRedisTemplate.hasKey("freeze" + user.getId())){
            Map parseObject = JSON.parseObject(stringRedisTemplate.opsForValue().get("freeze" + user.getId()), Map.class);
            System.out.println(parseObject.toString());
            freezingRange = (String) parseObject.get("freezingRange");
        }
        if("1".equals(freezingRange)){
            if(connectionFactory!=null){
                connectionFactory.setDatabase(0);
                stringRedisTemplate.setConnectionFactory(connectionFactory);
                connectionFactory.resetConnection();
                connectionFactory.afterPropertiesSet();
            }
            return ResponseEntity.status(401).body("已被冻结登录");
        }
        if(connectionFactory!=null){
            connectionFactory.setDatabase(0);
            stringRedisTemplate.setConnectionFactory(connectionFactory);
            connectionFactory.resetConnection();
            connectionFactory.afterPropertiesSet();
        }

        String token = JwtUtil.createToken(userMap);

        //5.以后用户每次请求过来的时候都需要解析token,获取用户信息,有点麻烦,为了减少麻烦,token作为key,user的json字符串作为value存入redis中,设置时效30天
        operations.set(ConstantUtil.USER_TOKEN + token, JSON.toJSONString(user), Duration.ofDays(30));

        //6.准备返回的数据(map),且返回
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("token", token);
        resultMap.put("isNew", isNew);

        //7.可以不写,建议把验证码删除一下
        stringRedisTemplate.delete(ConstantUtil.SMS_CODE + phone);

        //8.封装日志对象,发送到mq中
        Log log = new Log();
        log.setUserId(user.getId());
        log.setLogTime(DateUtil.formatDate(new Date()));
        log.setPlace("合肥闽商国贸");
        log.setEquipment("华为p70");
        //设置用户行为
        log.setType(isNew ? "0102" : "0101");
        //发送mq
        rabbitTemplate.convertAndSend("tanhua.log", log);

        return ResponseEntity.ok(resultMap);
    }

    public ResponseEntity checkVerificationCode(String verificationCode) {
        //1.获取用户id;
        Long userId = UserHolder.get().getId();
        //2.根据用户id获取用户信息
        User user = userService.getUser(userId);
        //从redis中获取验证码
        String redisCode = stringRedisTemplate.opsForValue().get(ConstantUtil.SMS_CODE + user.getMobile());
        //将redis中的验证码跟用户输入的验证码比较
        if (!StrUtil.equals(verificationCode, redisCode)) {
            return ResponseEntity.status(500).body("验证码输入有误");
        }
        // 清除短信验证码
        stringRedisTemplate.delete(ConstantUtil.SMS_CODE + user.getMobile());
        //返回结果
        Map<String, Object> map = new HashMap<>();
        map.put("verification", true);
        return ResponseEntity.ok(map);
    }

    public ResponseEntity saveUserInfo(UserInfo userInfo, String token) {
        //1.从token中获取当前登陆者
        User user = getUserFromToken(token);

        //2.判断登陆者是否为空,若为空返回401
        if (user == null) {
            return ResponseEntity.status(401).body(null);
        }

        //3.获取用户id,设置给userInfo
        userInfo.setId(user.getId());

        //4.远程service完成保存操作
        userInfoService.save(userInfo);
        return ResponseEntity.ok(null);
    }

    //从token中获取用户信息
    public User getUserFromToken(String token) {
        if (StrUtil.isNotBlank(token)) {
            String jsonStr = stringRedisTemplate.opsForValue().get(ConstantUtil.USER_TOKEN + token);

            if (StrUtil.isNotBlank(jsonStr)) {
                return JSON.parseObject(jsonStr, User.class);
            }
        }

        return null;
    }

    public ResponseEntity saveUserInfoHead(MultipartFile headPhoto, String token) throws IOException {
        //1.通过token获取用户
        //User user = getUserFromToken(token);
        //2.判断用户是否存在,若不存在返回401
        //if (user == null) {
        //    return ResponseEntity.status(401).body(null);
        //}
        User user = UserHolder.get();

        //3.先判断头像是否为人脸,若不是返回错误
        if (!aipFaceTemplate.detect(headPhoto.getBytes())) {
            return ResponseEntity.status(500).body(ErrorResult.faceError());
        }

        //4.将用户头像保存到oss上,返回url
        String url = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());

        //5.创建一个UserInfo,设置id和头像
        UserInfo userInfo = new UserInfo();
        userInfo.setId(user.getId());
        userInfo.setAvatar(url);//头像
        userInfo.setCoverPic(url);//封面

        //6.远程调用service完成更新操作
        userInfoService.update(userInfo);
        return ResponseEntity.ok(null);
    }

    public ResponseEntity findUserInfoById(Long id) {
        //1.远程调用service查询userInfo
        UserInfo userInfo = userInfoService.findById(id);

        //2.创建userInfoVo对象
        UserInfoVo vo = new UserInfoVo();

        //3.属性拷贝(我使用hutool中提供的工具类--参数1:有数据的对象,参数2:目标对象)
        BeanUtil.copyProperties(userInfo, vo);

        //4.返回userInfoVo
        return ResponseEntity.ok(vo);
    }

    public ResponseEntity updateUserInfo(UserInfo userInfo, String token) {
        //1.通过token获取用户
        //User user = getUserFromToken(token);
        //2.判断用户是否存在,若不存在返回401
        //if (user == null) {
        //    return ResponseEntity.status(401).body(null);
        //}
        User user = UserHolder.get();

        //3.若用户存在,给userInfo去设置id
        userInfo.setId(user.getId());

        //4.远程调用service完成更新操作
        userInfoService.update(userInfo);
        return ResponseEntity.ok(null);
    }



    /**
     * 添加好友
     *
     * @param friendId 好友id
     */
    public boolean contactUser(Long friendId) {
        Long userId = UserHolder.get().getId();

        String id = this.userLikeApi.saveUsers(userId, friendId);

        if (StrUtil.isNotEmpty(id)) {
            //注册好友关系到环信
            return this.huanXinTemplate.addContact(userId.toString(),friendId.toString());
        }

        return false;
    }

    public ResponseEntity counts() {
        //相互喜欢数量
        Integer friendCount = friendService.count(UserHolder.get().getId());
        //我喜欢的数量
        Integer loveCount = userLikeApi.findLoveCount(UserHolder.get().getId());
        //喜欢我的数量
        Integer fanCount = userLikeApi.findFanCount(UserHolder.get().getId());
        //CountsVo countsVo = new CountsVo(friendCount, loveCount, fanCount);
        UserLikeCountVo countsVo = new UserLikeCountVo(friendCount,loveCount,fanCount);

        return ResponseEntity.ok(countsVo);
    }

    public ResponseEntity findMyCountList(Integer type, Integer pageNum, Integer pageSize) {
        List<UserLikeVo> userLikeVoList = new ArrayList<>();
        Long userId = UserHolder.get().getId();//当前用户id
        PageBeanVo pageBeanVo = null;
        switch (type) {
            case 1: {
                pageBeanVo = friendService.contactsListByUserId(pageNum, pageSize, userId);
                List<Friend> friendList = (List<Friend>) pageBeanVo.getItems();
                if (CollectionUtil.isNotEmpty(friendList)) {
                    for (Friend friend : friendList) {
                        UserInfo userInfo = userInfoService.findById(friend.getFriendId());
                        UserLikeVo userLikeListVo = new UserLikeVo();
                        BeanUtils.copyProperties(userInfo, userLikeListVo);
                        Long score = recommendUserService.findScore(friend.getFriendId(), friend.getUserId());
                        userLikeListVo.setMatchRate(Math.toIntExact(score));
                        userLikeVoList.add(userLikeListVo);
                    }

                }
                break;
            }
            case 2: {
                pageBeanVo = userLikeApi.findLoveList(pageNum, pageSize, userId);
                List<UserLike> userLikeList = (List<UserLike>) pageBeanVo.getItems();
                if (CollectionUtil.isNotEmpty(userLikeList)) {
                    for (UserLike userLike : userLikeList) {
                        UserInfo userInfo = userInfoService.findById(userLike.getLikeUserId());
                        UserLikeVo userLikeListVo = new UserLikeVo();
                        BeanUtils.copyProperties(userInfo, userLikeListVo);
                        Long score = recommendUserService.findScore(userLike.getUserId(), userLike.getLikeUserId());
                        userLikeListVo.setMatchRate(Math.toIntExact(score));
                        userLikeVoList.add(userLikeListVo);
                    }
                }
                break;
            }
            case 3: {
                pageBeanVo = userLikeApi.findFanList(pageNum, pageSize, userId);
                List<UserLike> userLikeList = (List<UserLike>) pageBeanVo.getItems();
                if (CollectionUtil.isNotEmpty(userLikeList)) {
                    for (UserLike userLike : userLikeList) {
                        UserInfo userInfo = userInfoService.findById(userLike.getUserId());
                        UserLikeVo userLikeListVo = new UserLikeVo();
                        BeanUtils.copyProperties(userInfo, userLikeListVo);
                        Long score = recommendUserService.findScore(userLike.getUserId(), userLike.getLikeUserId());
                        userLikeListVo.setMatchRate(Math.toIntExact(score));
                        userLikeVoList.add(userLikeListVo);
                    }

                }
                break;
            }
            case 4: {
                pageBeanVo = visitorService.findHistoryList(pageNum, pageSize, userId);
                List<Visitor> visitorsList = (List<Visitor>) pageBeanVo.getItems();
                if (CollectionUtil.isNotEmpty(visitorsList)) {
                    for (Visitor visitors : visitorsList) {
                        UserInfo userInfo = userInfoService.findById(visitors.getVisitorUserId());
                        System.out.println(visitors.getVisitorUserId());
                        UserLikeVo userLikeListVo = new UserLikeVo();
                        BeanUtils.copyProperties(userInfo, userLikeListVo);
                        //缘分值
                        Long score = recommendUserService.findScore(visitors.getVisitorUserId(), UserHolder.get().getId());
                        userLikeListVo.setMatchRate(score.intValue());
                        userLikeVoList.add(userLikeListVo);
                        System.out.println(userLikeVoList);
                    }

                }
                break;
            }

        }
        pageBeanVo.setItems(userLikeVoList);
        return ResponseEntity.ok(pageBeanVo);

    }

    public ResponseEntity fansToFriend(Long fanId) {
        //删除粉丝
        userLikeApi.removeFans(fanId, UserHolder.get().getId());
        //插入朋友
        friendService.addContact(UserHolder.get().getId(), fanId);
        return ResponseEntity.ok(null);
    }

    public ResponseEntity removeLove(Long loveId) {
        // 1 判断用户点击的是哪个取消喜欢
        Boolean flag = friendService.isFriend(UserHolder.get().getId(), loveId);
        if (flag) {
            // 2 互相喜欢的---删除好友表的2条数据 userLike添加一个粉丝数据
            friendService.removeFriend(UserHolder.get().getId(), loveId);
            userLikeApi.addFans(UserHolder.get().getId(), loveId);
        } else {
            // 3 喜欢--直接删除喜欢的这个人
            userLikeApi.removeFans(UserHolder.get().getId(), loveId.longValue());
        }

        return ResponseEntity.ok(null);
    }
}